package O2;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FtpUtil {
	FTPClient ftpClient;
	private boolean isDownloading = true;
	// 枚举类UploadStatus代码

	public enum UploadStatus {
		Create_Directory_Fail, // 远程服务器相应目录创建失败
		Create_Directory_Success, // 远程服务器闯将目录成功
		Upload_New_File_Success, // 上传新文件成功
		Upload_New_File_Failed, // 上传新文件失败
		File_Exits, // 文件已经存在
		Remote_Bigger_Local, // 远程文件大于本地文件
		Upload_From_Break_Success, // 断点续传成功
		Upload_From_Break_Failed, // 断点续传失败
		Delete_Remote_Faild; // 删除远程文件失败
	}

	/**
	 * connectServer 连接ftp服务器
	 * 
	 * @throws java.io.IOException
	 * @param path
	 *            文件夹，空代表根目录
	 * @param password
	 *            密码
	 * @param user
	 *            登陆用户
	 * @param server
	 *            服务器地址
	 */
	public boolean connectServer(String server, String user, String password,
			String path) throws Exception {
		// server：FTP服务器的IP地址；user:登录FTP服务器的用户名
		// password：登录FTP服务器的用户名的口令；path：FTP服务器上的路径
		ftpClient = new FTPClient();
		ftpClient.connect(server);
		ftpClient.login(user, password);// 登录
		int reply = ftpClient.getReplyCode();
		System.out.println("reply:" + reply);
		if (!FTPReply.isPositiveCompletion(reply)) {
			ftpClient.disconnect();
			return false;
		}

		ftpClient.enterLocalPassiveMode();
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		System.out.println("ftpClient.:" + ftpClient.getControlEncoding());
		ftpClient.setControlEncoding("GBK");

		FTPClientConfig config = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
		config.setServerLanguageCode("zh");
		ftpClient.configure(config);
		// path是ftp服务下主目录的子目录
		if (path.length() != 0) {
			boolean change = ftpClient.changeWorkingDirectory(path);
			System.out.println("change:" + change + "  " + path);
			if (!change) {
				throw new Exception("在ftp服务器上变更工作目录" + path + "失败");
			}
		}
		return true;
	}

	/** */
	/**
	 * 上传文件到FTP服务器，支持断点续传
	 * 
	 * @param local
	 *            本地文件名称，绝对路径
	 * @param remote
	 *            远程文件路径，使用/home/directory1/subdirectory/file.ext或是
	 *            http://www.guihua.org /subdirectory/file.ext
	 *            按照Linux上的路径指定方式，支持多级目录嵌套，支持递归创建不存在的目录结构
	 * @return 上传结果
	 * @throws IOException
	 */
	public UploadStatus upload(String local, String remote) throws IOException {
		// 设置PassiveMode传输
		ftpClient.changeWorkingDirectory("/"); // 设置根目录
		ftpClient.enterLocalPassiveMode();
		// 设置以二进制流的方式传输
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		ftpClient.setControlEncoding("GBK");
		UploadStatus result;
		// 对远程目录的处理
		String remoteFileName = remote;
		if (remote.contains("/")) {
			remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
			// 创建服务器远程目录结构，创建失败直接返回
			if (CreateDirecroty(remote, ftpClient) == UploadStatus.Create_Directory_Fail) {
				return UploadStatus.Create_Directory_Fail;
			}
		}
		result = uploadFile(remoteFileName, new File(local), ftpClient);
		ftpClient.changeWorkingDirectory("/"); // 上传完毕重新设置为根目录
		return result;
	}

	/** */
	/**
	 * 断开与远程服务器的连接
	 * 
	 * @throws IOException
	 */
	public void disconnect() throws IOException {
		if (ftpClient.isConnected()) {
			ftpClient.disconnect();
		}
	}

	/** */
	/**
	 * 上传文件到服务器,新上传和断点续传
	 * 
	 * @param remoteFile
	 *            远程文件名，在上传之前已经将服务器工作目录做了改变
	 * @param localFile
	 *            本地文件 File句柄，绝对路径
	 * @param processStep
	 *            需要显示的处理进度步进值
	 * @param ftpClient
	 *            FTPClient 引用
	 * @return
	 * @throws IOException
	 */
	public UploadStatus uploadFile(String remoteFile, File localFile,
			FTPClient ftpClient) throws IOException {
		UploadStatus status;

		RandomAccessFile raf = new RandomAccessFile(localFile, "r");
		OutputStream out = ftpClient.appendFileStream(new String(remoteFile
				.getBytes("GBK"), "iso-8859-1"));

		byte[] bytes = new byte[4096];
		int c;
		while ((c = raf.read(bytes)) != -1) {
			out.write(bytes, 0, c);
		}
		out.flush();
		raf.close();
		out.close();
		boolean result = ftpClient.completePendingCommand();
		status = result ? UploadStatus.Upload_New_File_Success
				: UploadStatus.Upload_New_File_Failed;
		return status;
	}

	/** */
	/**
	 * 递归创建远程服务器目录
	 * 
	 * @param remote
	 *            远程服务器文件绝对路径
	 * @param ftpClient
	 *            FTPClient 对象
	 * @return 目录创建是否成功
	 * @throws IOException
	 */
	public UploadStatus CreateDirecroty(String remote, FTPClient ftpClient)
			throws IOException {
		UploadStatus status = UploadStatus.Create_Directory_Success;
		String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
		if (!directory.equalsIgnoreCase("/")
				&& !ftpClient.changeWorkingDirectory(new String(directory
						.getBytes("GBK"), "iso-8859-1"))) {
			// 如果远程目录不存在，则递归创建远程服务器目录
			int start = 0;
			int end = 0;
			if (directory.startsWith("/")) {
				start = 1;
			} else {
				start = 0;
			}
			end = directory.indexOf("/", start);
			while (true) {
				String subDirectory = new String(remote.substring(start, end)
						.getBytes("GBK"), "iso-8859-1");
				if (!ftpClient.changeWorkingDirectory(subDirectory)) {
					if (ftpClient.makeDirectory(subDirectory)) {
						System.err.println("###########     " + subDirectory);
						ftpClient.changeWorkingDirectory(subDirectory); // TODO
					} else {
						System.out.println("创建目录失败");
						return UploadStatus.Create_Directory_Fail;
					}
				}

				start = end + 1;
				end = directory.indexOf("/", start);

				// 检查所有目录是否创建完毕
				if (end <= start) {
					break;
				}
			}
		}
		return status;
	}

	public void stopDownload() {
		isDownloading = false;
	}

	public boolean download(String filename, String newfilename)
			throws Exception {
		BufferedOutputStream outStream = null;
		boolean success = false;
		try {
			String dir = newfilename.substring(0,
					newfilename.lastIndexOf('/') + 1);
			Func.makeDir(dir);
			java.io.File outfile = new java.io.File(newfilename);
			if (outfile.exists()) {
				outfile.delete();
			}
			outfile.createNewFile();
			System.out.println("newfilename:" + newfilename);
			System.out.println("ftpfilename:" + filename);
			outStream = new BufferedOutputStream(new FileOutputStream(
					newfilename));
			// String onlyFileName=filename.substring(filename.lastIndexOf('/')
			// + 1);
			// System.out.println("onlyFileName:"+onlyFileName);
			filename = new String(filename.getBytes("GBK"), "ISO-8859-1");
			success = this.ftpClient.retrieveFile(filename, outStream);
			System.out.println("success:" + success);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			if (null != outStream) {
				try {
					outStream.flush();
					outStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		if (success == false) {
			throw new Exception("文件" + filename + "下载失败");
		}
		return success;
	}

	/**
	 * download 从ftp下载文件到本地
	 * 
	 * @throws java.lang.Exception
	 * @return
	 * @param newfilename
	 *            本地生成的文件名
	 * @param filename
	 *            服务器上的文件名
	 */

	/**
	 * 取得某个目录下的所有文件列表
	 * 
	 * @throws Exception
	 * 
	 */
	public List getFileList(String path) throws Exception {
		path = path.replaceAll("\\\\", "/");
		if (!path.endsWith("/")) {
			path += "/";
		}
		List list = new ArrayList();
		try {
			FTPFile[] allFile = this.ftpClient.listFiles(path);
			for (int i = 0; i < allFile.length; i++) {
				String filename = allFile[i].getName();
				if (allFile[i].isDirectory()) {
					String currentPath = path + filename + "/";
					list.addAll(getFileList(currentPath));
				} else {
					// System.out.println("是文件："+filename);
					String currentFilename = path + filename;
					list.add(currentFilename);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
		return list;
	}

	/**
	 * closeServer 断开与ftp服务器的链接
	 * 
	 * @throws java.io.IOException
	 */
	public void closeServer() throws IOException {

		if (ftpClient == null)
			return;
		try {
			ftpClient.logout();
		} catch (IOException e) {
			e.printStackTrace();
			return;
		} finally {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException ioe) {
				}
			}
		}

	}

	public static void test2() throws Exception {

		String export = "/Export/";
		int len = export.length();
		String path = "D:\\z";
		path = path.replaceAll("\\\\", "/");
		FtpUtil ftpUtil = new FtpUtil();
		ftpUtil.connectServer("10.1.4.109", "9AA3maomao", "McbkX47x", "");
		List<String> filelists = Func.getFileList(path);
		List<String> remotefilelists = new ArrayList<String>();
		for (String localname : filelists) {
			localname = localname.replaceAll("\\\\", "/");
			String remotename = localname.replaceAll(path, "");
			remotefilelists.add(remotename);
			ftpUtil.upload(localname, remotename);
			// System.out.println(remotename);
		}
		ftpUtil.closeServer();
	}

	public static void main(String[] args) throws Exception {
		test2();
	}
}